package com.alibaba.dubbo.dynamic.service;

import com.alibaba.dubbo.common.URL;
import com.alibaba.dubbo.config.ApplicationConfig;
import com.alibaba.dubbo.config.spring.ReferenceBean;
import com.alibaba.dubbo.dynamic.config.DynamicExportConfig;
import com.alibaba.dubbo.remoting.exchange.Response;
import com.alibaba.dubbo.remoting.zookeeper.ZookeeperClient;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.apache.zookeeper.KeeperException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.io.IOException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Created by wuyu on 2016/8/8.
 */
@RestController
@RequestMapping(value = "/dynamic")
public class DynamicExportController implements DisposableBean {


    @Autowired
    ApplicationContext applicationContext;

    @Autowired
    private ZookeeperClient zookeeperClient;

    @Value("${server.port}")
    private int port;

    private String dynamicServicePath = "/dubbo/com.alibaba.dubbo.dynamic.service.DynamicExportService/providers";


    private Map<String, ReferenceBean<DynamicExportService>> serviceMap = new ConcurrentHashMap<String, ReferenceBean<DynamicExportService>>();


    @GetMapping(value = "/listDynamicService")
    public List<JSONObject> listDynamicService() throws IOException, KeeperException, InterruptedException {
        List<String> children = zookeeperClient.getChildren(dynamicServicePath);
        List<JSONObject> dys = new ArrayList<JSONObject>();
        for (String dy : children) {
            URL url = URL.valueOf(URL.decode(dy));
            JSONObject json = new JSONObject();
            String application = url.getParameter("application");
            String timestamp = url.getParameter("timestamp");
            json.put("port", url.getPort());
            json.put("host", url.getHost());
            json.put("url", url.toServiceString());
            json.put("fullUrl", url.toFullString());
            json.put("application", application);
            json.put("timestamp", timestamp);

            dys.add(json);
        }
        return dys;
    }

    @GetMapping(value = "/listDynamicBean")
    public List<Map<String, Object>> listDynamicBean() throws InterruptedException, IOException, KeeperException {
        List<JSONObject> dynamicServices = listDynamicService();
        List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

        for (JSONObject json : dynamicServices) {
            String url = json.getString("url");
            List<Map<String, Object>> maps = getDynamicExportService(url).listDynamicBean();
            for (Map<String, Object> map : maps) {
                map.put("dynamicServiceUrl", url);
            }
            list.addAll(maps);
        }
        return list;
    }


    @GetMapping(value = "/export")
    public ResponseEntity<Map<String, Map<String, Object>>> export(@RequestBody JSONObject json) {
        JSONArray urls = json.getJSONArray("urls");
        JSONArray jarsJson = json.getJSONArray("jars");
        JSONArray configsJson = json.getJSONArray("configs");
        //Boolean renewClassLoader = json.getBoolean("renewClassLoader");
        List<DynamicExportConfig> dynamicExportConfigs = new ArrayList<DynamicExportConfig>();
        for (int i = 0; i < configsJson.size(); i++) {
            dynamicExportConfigs.add(configsJson.getObject(i, DynamicExportConfig.class));
        }
        List<String> jars = new ArrayList<String>();
        for (int i = 0; i < jarsJson.size(); i++) {
            jars.add(jarsJson.getString(i));
        }
        Map<String, Map<String, Object>> map = new HashMap<String, Map<String, Object>>();

        for (int i = 0; i < urls.size(); i++) {
            String url = urls.getString(i);
            Map<String, Object> export = getDynamicExportService(url).export(jars, dynamicExportConfigs);
            URL url1 = URL.valueOf(url);
            map.put(url1.getAddress(), export);
        }
        return new ResponseEntity<Map<String, Map<String, Object>>>(map, HttpStatus.OK);
    }

    @GetMapping(value = "/unexport")
    public ResponseEntity<String> unexport(@RequestParam(value = "id") String id, @RequestParam(value = "url") String url) {
        DynamicExportService dynamicExportService = getDynamicExportService(url);
        if (dynamicExportService != null) {
            dynamicExportService.unexport(Arrays.asList(id));
        }
        return new ResponseEntity<String>(HttpStatus.OK);
    }


    public DynamicExportService getDynamicExportService(String url) {
        ReferenceBean<DynamicExportService> cacheBean = serviceMap.get(url);
        if (cacheBean != null) {
            return cacheBean.get();
        }
        ReferenceBean<DynamicExportService> referenceBean = new ReferenceBean<DynamicExportService>();
        referenceBean.setApplicationContext(this.applicationContext);
        referenceBean.setInterface(DynamicExportService.class);
        referenceBean.setUrl(url);
        referenceBean.setApplication(new ApplicationConfig("dynamic-ref"));
        serviceMap.put(url, referenceBean);
        return referenceBean.get();
    }


    public void destroy() throws Exception {
        for (String key : serviceMap.keySet()) {
            try {
                serviceMap.remove(key).destroy();
            } catch (Exception e) {
            }
        }
    }


}
